﻿//---------------------------------------------------------------------------
// <copyright file="RibbonGroupsContainer.cs" company="Microsoft Corporation">
//     Copyright (C) Microsoft Corporation.  All rights reserved.
// </copyright>
//---------------------------------------------------------------------------

namespace Microsoft.Windows.Controls.Ribbon
{
    #region Using declarations

    using System.Windows;
    using System.Windows.Controls;

    #endregion

    /// <summary>
    ///   The panel that contains the RibbonGroups of a RibbonTab.
    /// </summary>
    internal class RibbonGroupsContainer : StackPanel
    {
        #region Fields

        /// <summary>
        ///   A cached copy of the RibbonGroupContainer's constraint from the previous layout pass.
        /// </summary>
        private Size _cachedConstraint;

        /// <summary>
        ///   A cached copy of the RibbonGroupsContainer's desired size from the previous layout pass.
        /// </summary>
        private Size _cachedDesiredSize;
        
        /// <summary>
        ///   The parent RibbonTab of this RibbonGroupsContainer.
        /// </summary>
        private RibbonTab _ribbonTab;

        #endregion

        #region Constructors

        /// <summary>
        ///   Initializes static members of the RibbonGroupsContainer class.
        /// </summary>
        static RibbonGroupsContainer()
        {
            OrientationProperty.OverrideMetadata(typeof(RibbonGroupsContainer), new FrameworkPropertyMetadata(Orientation.Horizontal));
        }

        /// <summary>
        ///   Initializes a new instance of the RibbonGroupsContainer class.
        /// </summary>
        /// <param name="ribbonTab">The parent RibbonTab.</param>
        public RibbonGroupsContainer(RibbonTab ribbonTab)
        {
            _ribbonTab = ribbonTab;
        }

        #endregion

        #region Protected Methods

        /// <summary>
        ///   Returns a collection of the panel's UIElements.
        /// </summary>
        /// <param name="logicalParent">The logical parent of the collection to be created.</param>
        /// <returns>Returns an ordered collection of elements that have the specified logical parent.</returns>
        protected override UIElementCollection CreateUIElementCollection(FrameworkElement logicalParent)
        {
            return new UIElementCollection(this, _ribbonTab);
        }

        /// <summary>
        ///   Measures all of the RibbonGroups, and asks them to resize themselves appropriately
        ///   to fit within the available room in the GroupsContainer.
        /// </summary>
        /// <param name="constraint">The available size that this element can give to child elements.</param>
        /// <returns>
        ///   The size that the groups container determines it needs during layout, based
        ///   on its calculations of child element sizes.
        /// </returns>
        protected override Size MeasureOverride(Size constraint)
        {
            Size desiredSize = new Size();

            desiredSize = base.MeasureOverride(constraint);

            // If the constraint and desired size are equal to those in the cache, skip
            // this layout measure pass.
            if ((constraint != _cachedConstraint) || (desiredSize != _cachedDesiredSize))
            {
                _cachedConstraint = constraint;
                _cachedDesiredSize = desiredSize;

                // If we have more available space - try to expand groups
                while (this.GetChildrensTotalWidth() <= constraint.Width)
                {
                    bool hasMoreVariants = _ribbonTab.IncreaseNextGroupSize();
                    if (hasMoreVariants)
                    {
                        desiredSize = base.MeasureOverride(constraint);
                    }
                    else
                    {
                        break;
                    }
                }

                // If not enough space - go to next variant
                while (this.GetChildrensTotalWidth() > constraint.Width)
                {
                    bool hasMoreVariants = _ribbonTab.DecreaseNextGroupSize();
                    if (hasMoreVariants)
                    {
                        desiredSize = base.MeasureOverride(constraint);
                    }
                    else
                    {
                        break;
                    }
                }
            }

            //// Scroll if not enough space

            return desiredSize;
        }

        #endregion

        #region Private Methods

        /// <summary>
        ///   Calculates the total width of all of the RibbonGroups in the RibbonTab.
        /// </summary>
        /// <returns>Returns the total width of all of the RibbonGroups in the RibbonTab.</returns>
        private double GetChildrensTotalWidth()
        {
            double result = 0;
            foreach (UIElement child in this.Children)
            {
                result += child.DesiredSize.Width;
            }

            return result;
        }

        #endregion
    }
}